package lab.cadl.lirui.markdown.core.utils

object Html5Entities {
    private val NUMERIC_PATTERN = Regex("^&#([Xx]?)([1-9a-fA-F]+);")
    private val NAMED_PATTERN = Regex("^&(\\w+);")
    private const val ENTITY_PATH = "lab/cadl/lirui/markdown/core/entities.properties"
    private val NAMED_MAP = readEntities()

    fun entityToString(entity: String): String {
        return tryNumeric(entity) ?: tryName(entity)
    }

    private fun tryNumeric(entity: String): String? {
        val match = NUMERIC_PATTERN.matchEntire(entity) ?: return null

        val base = if (match.groupValues[1].isBlank()) {
            10
        } else {
            16
        }

        val codePoint = Integer.valueOf(match.groupValues[2], base)
        return if (codePoint == 0) {
            "\uFFFD"
        } else {
            Character.toChars(codePoint).joinToString("")
        }
    }

    private fun tryName(entity: String): String {
        val match = NAMED_PATTERN.matchEntire(entity)?: return entity
        return NAMED_MAP[match.groupValues[1]] ?: entity
    }

    private fun readEntities(): Map<String, String> {
        val entities = mutableMapOf<String, String>()
        javaClass.classLoader.getResourceAsStream(ENTITY_PATH).bufferedReader().use {
            for (line in it.lines().map { it.trim() }) {
                val index = line.indexOf('=')
                if (index == -1) {
                    continue
                }

                val key = line.substring(0, index)
                val value = line.substring(index + 1, line.length)
                entities[key] = value
            }
        }

        return entities
    }
}